#include "ints.h"

/** Installs the ASM written function 'irq_func' as the interrupt
 * handler associated with interrupt 'irq', updating the 'old_irq'
 * structure with the current interrupt handler.  Returns 0 on success
 * or -1 on error, in which case the original interrupt handler
 * remains installed.
 * 
 * See reinstall_asm_irq_handler() to reinstall the original handler.
 */

 int install_asm_irq_handler(int irq, void (*irq_func)(void), _go32_dpmi_seginfo *old_irq) {
        _go32_dpmi_seginfo new_vec;
        _go32_dpmi_get_protected_mode_interrupt_vector( IRQ_VECTOR(irq) , old_irq);
        new_vec.pm_selector = _go32_my_cs();
        new_vec.pm_offset = (unsigned long) irq_func;
        _go32_dpmi_set_protected_mode_interrupt_vector ( IRQ_VECTOR(irq) , &new_vec);
        return 0;
}

/** Installs the C written 'irq_func' interrupt handler at the
 * interrupt handler associated with interrupt 'irq', updating the
 * old_irq structure with the current interrupt handler.  Returns 0 on
 * success or -1 on error, in which case the original interrupt
 * handler remains installed.
 * 
 * See reinstall_c_irq_handler() to reinstall the original handler.
 */
int install_c_irq_handler(int irq, void (*irq_func)(void), _go32_dpmi_seginfo *old_irq, _go32_dpmi_seginfo *new_vec) {
        _go32_dpmi_get_protected_mode_interrupt_vector( IRQ_VECTOR(irq) , old_irq);
        new_vec->pm_selector = _go32_my_cs();
        new_vec->pm_offset = (unsigned long) irq_func;
        _go32_dpmi_allocate_iret_wrapper(new_vec);
        _go32_dpmi_set_protected_mode_interrupt_vector ( IRQ_VECTOR(irq) ,new_vec);
        return 0;
}

/** Reinstalls the interrupt handler specified in 'old_irq' for interrupt
 * 'irq'. See install_asm_irq_handler().
 */
void reinstall_asm_irq_handler(int irq, _go32_dpmi_seginfo *old_irq) {
        _go32_dpmi_set_protected_mode_interrupt_vector( IRQ_VECTOR(irq) , old_irq);
}

/** Reinstalls the interrupt handler specified in 'old_irq' for interrupt
 * 'irq'. See install_c_irq_handler().
 */
void reinstall_c_irq_handler(int irq, _go32_dpmi_seginfo *old_irq, _go32_dpmi_seginfo *new_irq) {
        _go32_dpmi_set_protected_mode_interrupt_vector(IRQ_VECTOR(irq), old_irq);
        _go32_dpmi_free_iret_wrapper(new_irq);
}

/** Mask the bit corresponding to 'irq', disabling its interrupts.
 * Returns the previous irq status
 * The correct PIC is used.
 */
int disable_irq(int irq) {
        // Escrever um 1 no bit de mascara
        int old = 0;
        if (irq > 7) {
                // Usar pic-2
                old = inportb(PIC2_MASK);
                outportb(PIC2_MASK, old | IRQ_MASK_BIT(irq) );
        } else {
                // Usar pic-1
                old = inportb(PIC1_MASK);
                outportb(PIC1_MASK, old | IRQ_MASK_BIT(irq));
        }
        return old;
}

/** Unmask the bit corresponding to 'irq', enabling its interrupts.
 * The correct PIC is used.
*/
void enable_irq(int irq) {
        // Escrever um 0
        int old = 0;
        if (irq > 7) {
                // Usar pic-2
                old = inportb(PIC2_MASK);
                outportb(PIC2_MASK, old & (~IRQ_MASK_BIT(irq)) );
        } else {
                // Usar pic-1
                old = inportb(PIC1_MASK);
                outportb(PIC1_MASK, old & (~IRQ_MASK_BIT(irq)) );
        }
}
